using System;
using System.Collections.Generic;
using QFramework.Framework.ResKit.Res;
using Object = UnityEngine.Object;

namespace QFramework.Framework.ResKit
{
    /// <summary>
    ///     资源服务类：路由设计模式
    /// </summary>
    public class ResLoader
    {
        #region API

        public T LoadSync<T>(string assetName) where T : Object
        {
            return DoLoadSync<T>(assetName);
        }

        public T LoadSync<T>(string assetBundleName, string assetName) where T : Object
        {
            return DoLoadSync<T>(assetName, assetBundleName);
        }

        public void LoadAsync<T>(string assetName, Action<T> onLoaded) where T : Object
        {
            DoLoadAsync(assetName, null, onLoaded);
        }

        public void LoadAsync<T>(string assetBundleName, string assetName, Action<T> onLoaded) where T : Object
        {
            DoLoadAsync(assetName, assetBundleName, onLoaded);
        }

        public void ReleaseAll()
        {
            _resRecord.ForEach(loadedAsset => { loadedAsset.Release(); });

            _resRecord.Clear();
        }

        #endregion

        #region Private

        private T DoLoadSync<T>(string assetName, string assetBundleName = null) where T : Object
        {
            var res = GetRes(assetName);

            if (res != null)
                switch (res.State)
                {
                    case ResState.Loading:
                        throw new Exception(string.Format("请不要在异步加载资源 {0} 时，进行 {0} 的同步加载", res.Name));
                    case ResState.Loaded:
                        return res.Asset as T;
                }

            // 加载资源
            res = CreateRes(assetName, assetBundleName);

            res.LoadSync();

            return res.Asset as T;
        }

        private void DoLoadAsync<T>(string assetName, string ownerBundleName, Action<T> onLoaded) where T : Object
        {
            var res = GetRes(assetName);

            Action<Res.Res> onResLoaded = null;

            onResLoaded = loadedRes =>
            {
                onLoaded(loadedRes.Asset as T);

                loadedRes.UnRegisterOnLoadedEvent(onResLoaded);
            };

            if (res != null)
            {
                if (res.State == ResState.Loading)
                    res.RegisterOnLoadedEvent(onResLoaded);
                else if (res.State == ResState.Loaded)
                    onLoaded(res.Asset as T);

                return;
            }

            // 加载资源
            res = CreateRes(assetName, ownerBundleName);

            res.RegisterOnLoadedEvent(onResLoaded);

            res.LoadAsync();
        }

        /// <summary>
        ///     当前资源记录
        /// </summary>
        private readonly List<Res.Res> _resRecord = new();

        private Res.Res GetRes(string assetName)
        {
            // 查询 当前资源记录
            var res = GetResFromRecord(assetName);
            if (res != null) return res;

            // 查询 全局资源池
            res = GetResFromResMgr(assetName);
            if (res != null)
            {
                AddResToRecord(res);
                return res;
            }

            return null;
        }

        private Res.Res CreateRes(string assetName, string ownerBundleName = null)
        {
            var res = ResFactory.CreateRes(assetName, ownerBundleName);

            ResMgr.Instance.SharedLoadedReses.Add(res);

            AddResToRecord(res);

            return res;
        }

        private Res.Res GetResFromRecord(string assetName)
        {
            return _resRecord.Find(loadedAsset => loadedAsset.Name == assetName);
        }

        private Res.Res GetResFromResMgr(string assetName)
        {
            return ResMgr.Instance.SharedLoadedReses.Find(loadedAsset => loadedAsset.Name == assetName);
        }

        private void AddResToRecord(Res.Res resFromResMgr)
        {
            _resRecord.Add(resFromResMgr);
            resFromResMgr.Retain();
        }

        #endregion
    }
}